﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Data;
using Data.Realm;
using AIMLbot.Utils;
using CsClient;

namespace CsClient
{
    static class Agent
    {
        static int mojaEnergia; // Aktualna energia agenta.
        static Wspolrzedne pozycjaAgenta; // Aktualna pozycja agenta.
        static int kierunekPatrzenia; // Aktualnie oglądana strona świata. 0 - północ, 1 - wschód,
                                      // 2 - południe, 3 - zachód
        static int aktualnaWysokosc; // Wysokość pola na którym aktualnie stoi agent.
        static String nazwaAgenta; // Nazwa naszego agenta w postaci: "grupa.imie"
        public static WorldParameters cennikSwiata; // Informacje o Świecie.
        static int najmniejszyKoszt, najwiekszyKoszt; // Najmniejszy i najwiekszy koszt działania
                                                      // agenta w Świecie.

        static public void SkonstruujAgenta(String nazwaGrupy, String imie, WorldParameters pobranyCennik)
        {
            nazwaAgenta = imie + "." + nazwaGrupy;
            cennikSwiata = pobranyCennik;
            mojaEnergia = pobranyCennik.initialEnergy;
            pozycjaAgenta = new Wspolrzedne(0, 0);
            kierunekPatrzenia = 0;
            aktualnaWysokosc = 0;
            ZnanaMapa.dodajPole(new Wspolrzedne(0, 0), 0, 0, false);

            #region Określanie Ekstremów Cennika

            najwiekszyKoszt = cennikSwiata.moveCost;
            najmniejszyKoszt = cennikSwiata.moveCost;
            if (najmniejszyKoszt > cennikSwiata.rotateCost)
            {
                najmniejszyKoszt = cennikSwiata.rotateCost;
            }
            else
            {
                najwiekszyKoszt = cennikSwiata.rotateCost;
            }
            if (najmniejszyKoszt > cennikSwiata.speakCost)
            {
                najmniejszyKoszt = cennikSwiata.speakCost;
            }
            if (najwiekszyKoszt < cennikSwiata.speakCost)
            {
                najwiekszyKoszt = cennikSwiata.speakCost;
            }

            #endregion

            #region Ustawienie AIMLbot z Komunikacja.cs

            Komunikacja.agentAIML = new AIMLbot.Bot();
            Komunikacja.agentAIML.loadSettings();
            Komunikacja.agentAIML.loadAIMLFromFiles();

            #endregion

        }

        #region Pytania Egzystencjalne

        static public bool czyLepiejUmrzec()
        {
            if ((mojaEnergia < najmniejszyKoszt) || (mojaEnergia < cennikSwiata.moveCost))
                return true;
            return false;
        }

        static public bool czyLepiejIscDoZrodla()
        {
            if (ZnanaMapa.kosztDoEnergii != -1)
            {
                if (ZnanaMapa.najblizszaNieskonczonaEnergia != null)
                {
                    if (Wspolrzedne.toSamoPole(ZnanaMapa.najblizszaEnergia, ZnanaMapa.najblizszaNieskonczonaEnergia))
                    {
                        if (mojaEnergia >= ZnanaMapa.kosztDoEnergii + najwiekszyKoszt + 4 * cennikSwiata.speakCost)
                            return false;
                        else
                            return true;
                    }
                }
                else
                {
                    if (mojaEnergia >= cennikSwiata.initialEnergy - (ZnanaMapa.kosztDoEnergii))
                        return false;
                    else
                        return true;
                }
            }
            return false;
        }

        #endregion

        #region Poruszanie się

        static public void przesunDoPrzodu()
        {
            Przejscie obecne;
            switch (kierunekPatrzenia)
            {
                case 0:
                    obecne = ZnanaMapa.znajdzPole(pozycjaAgenta).getPolnocne();
                    aktualnaWysokosc = obecne.getDokad().getWysokosc();
                    pozycjaAgenta.incY();
                    break;
                case 1:
                    obecne = ZnanaMapa.znajdzPole(pozycjaAgenta).getWschodnie();
                    aktualnaWysokosc = obecne.getDokad().getWysokosc();
                    pozycjaAgenta.incX();
                    break;
                case 2:
                    obecne = ZnanaMapa.znajdzPole(pozycjaAgenta).getPoludniowe();
                    aktualnaWysokosc = obecne.getDokad().getWysokosc();
                    pozycjaAgenta.decY();
                    break;
                case 3:
                    obecne = ZnanaMapa.znajdzPole(pozycjaAgenta).getZachodnie();
                    aktualnaWysokosc = obecne.getDokad().getWysokosc();
                    pozycjaAgenta.decX();
                    break;
            }
        }

        static public void obrocWLewo()
        {
            kierunekPatrzenia = (kierunekPatrzenia + 3) % 4;
            mojaEnergia -= cennikSwiata.rotateCost;
        }

        static public void obrocWPrawo()
        {
            kierunekPatrzenia = (kierunekPatrzenia + 1) % 4;
            mojaEnergia -= cennikSwiata.rotateCost;
        }

        static private void wykonajKrokKu(Wspolrzedne cel)
        {
            int[] wynik = ZnanaMapa.znajdzNajtanszaDroge(cel);
            if (wynik[1] == -1)
                return;
            switch (kierunekPatrzenia)
            {
                case 0:
                    switch (wynik[1])
                    {
                        case 1:
                            Program.RotateRight();
                            break;
                        case 3:
                            Program.RotateLeft();
                            break;
                        case 2:
                            if (new Random().Next(2) == 1)
                            {
                                Program.RotateLeft();
                                Program.RotateLeft();
                            }
                            else
                            {
                                Program.RotateRight();
                                Program.RotateRight();
                            }
                            break;
                    }
                    Program.StepForward();
                    break;
                case 1:
                    switch (wynik[1])
                    {
                        case 2:
                            Program.RotateRight();
                            break;
                        case 0:
                            Program.RotateLeft();
                            break;
                        case 3:
                            if (new Random().Next(2) == 1)
                            {
                                Program.RotateLeft();
                                Program.RotateLeft();
                            }
                            else
                            {
                                Program.RotateRight();
                                Program.RotateRight();
                            }
                            break;
                    }
                    Program.StepForward();
                    break;
                case 2:
                    switch (wynik[1])
                    {
                        case 3:
                            Program.RotateRight();
                            break;
                        case 1:
                            Program.RotateLeft();
                            break;
                        case 0:
                            if (new Random().Next(2) == 1)
                            {
                                Program.RotateLeft();
                                Program.RotateLeft();
                            }
                            else
                            {
                                Program.RotateRight();
                                Program.RotateRight();
                            }
                            break;
                    }
                    Program.StepForward();
                    break;
                case 3:
                    switch (wynik[1])
                    {
                        case 0:
                            Program.RotateRight();
                            break;
                        case 2:
                            Program.RotateLeft();
                            break;
                        case 1:
                            if (new Random().Next(2) == 1)
                            {
                                Program.RotateLeft();
                                Program.RotateLeft();
                            }
                            else
                            {
                                Program.RotateRight();
                                Program.RotateRight();
                            }
                            break;
                    }
                    Program.StepForward();
                    break;
            }
        }

        #endregion

        static public void Zachowanie()
        {
            DateTime poczatek = DateTime.Now;
            Program.Look();
            if (3 * cennikSwiata.rotateCost < (mojaEnergia - cennikSwiata.rotateCost))
            {
                if (new Random().Next(2) == 1)
                {
                    Program.RotateLeft();
                    Program.RotateLeft();
                    Program.RotateLeft();
                }
                else
                {
                    Program.RotateRight();
                    Program.RotateRight();
                    Program.RotateRight();
                }
            }
            bool loop = true;
            Wspolrzedne cel = null;
            while (loop)
            {
                if (Program.komunikatDoWyslania != null)
                {
                    Program.Speak(Program.komunikatDoWyslania);
                    Program.komunikatDoWyslania = null;
                }
                //Program.Czekaj(1); //FUFUFUFUFU A JA ZASTANAWIAŁEM SIĘ CZEMU TAK WOLNO DZIAŁA!!! xP
                //Console.WriteLine("Moja energia: " + myEnergy);
                if (czyLepiejUmrzec())
                {
                    Console.WriteLine("Mam za mało energii aby cokolwiek zrobić! Ginę!");
                    break;
                }
                cel = ZnanaMapa.najblizszeUkrytePole();
                if (cel == null)
                {
                    Console.WriteLine("Ile moglem, tyle zbadalem!\nWIN!");
                    break;
                }
                if (ZnanaMapa.najblizszaEnergia != null)
                {
                    if(czyLepiejIscDoZrodla()){
                            cel = ZnanaMapa.najblizszaEnergia;
                    }
                }
                Agent.wykonajKrokKu(cel);
            }
            DateTime end = DateTime.Now;
            ZnanaMapa.show();
            Console.WriteLine("Total living time: " + end.Subtract(poczatek).ToString());
            Console.WriteLine("Press SPACEBAR to end!");
            loop = true;
            while (loop)
            {
                switch (Console.ReadKey().Key)
                {
                    case ConsoleKey.Spacebar: loop = false;
                        break;
                    default:
                        break;
                }
            }
        }

        #region Get'y Set'y oraz zmiany atrybutów

        static public Wspolrzedne getPozycjaAgenta()
        {
            return pozycjaAgenta;
        }

        static public int getKierunekPatrzenia()
        {
            return kierunekPatrzenia;
        }
        
        static public int getWysokosc()
        {
            return aktualnaWysokosc;
        }

        static public int getEnergia()
        {
            return mojaEnergia;
        }

        static public bool odejmijEnergie(int iloscEnergii)
        {
            if (mojaEnergia >= iloscEnergii)
            {
                mojaEnergia -= iloscEnergii;
                return true;
            }
            return false;
        }

        static public void powiedzialesCos()
        {
            mojaEnergia -= cennikSwiata.speakCost;
        }

        static public void dodajEnergie(int iloscEnergii)
        {
            mojaEnergia += iloscEnergii;
        }

        static public String getNazwa()
        {
            return nazwaAgenta;
        }

        #endregion
    }
}
